#include <chrono>
#include <exception>
// #include <variant>
#include "../co_async/steps/co_async/debug.hpp"
#include <coroutine>
#include <deque>
#include <queue>
#include <thread>

/**
 * 【【C++20】从0开始自制协程库，有手就行（上）】https://www.bilibili.com/video/BV1Yz421Z7rZ
 1:26:23
 *
 */

using namespace std::chrono_literals;

template <class T>
union Uninitialized {
    T mvalue;

    Uninitialized() noexcept {}

    Uninitialized(Uninitialized &&) = delete;

    ~Uninitialized() noexcept {}

    T moveValue() {
        T ret(std::move(mvalue));
        mvalue.~T();
        return ret;
    }

    template <class... Ts>
    void putValue(Ts &&...args) {
        new (std::addressof(mvalue)) T(std::forward<Ts>(args)...);
    }
};

// struct RepeatAwaiter {
//     bool await_ready() const noexcept {
//         return false;
//     }

//     std::coroutine_handle<>
//     await_suspend(std::coroutine_handle<> coroutine) const noexcept {
//         if (coroutine.done()) {
//             return std::noop_coroutine();
//         } else {
//             return coroutine;
//         }
//     }

//     void await_resume() const noexcept {}
// };

struct PreviousAwaiter {
    std::coroutine_handle<> mPrevious = nullptr;

    constexpr bool await_ready() const noexcept {
        return false;
    }

    constexpr std::coroutine_handle<>
    await_suspend(std::coroutine_handle<> coroutine) const noexcept {
        if (mPrevious) {
            return mPrevious;
        } else {
            return std::noop_coroutine();
        }
    }

    constexpr void await_resume() const noexcept {}
};

template <class T>
struct Promise {
    auto initial_suspend() {
        return std::suspend_always();
    }

    auto final_suspend() noexcept {
        return PreviousAwaiter(mPrevious);
    }

    void unhandled_exception() {
        debug(), "unhandled_exception";

        mException = std::current_exception();
    }

    void return_value(T &&ret) {
        mResult.putValue(std::move(ret));
    }

    void return_value(T const &ret) {
        mResult.putValue(ret);
    }

    // auto yield_value(T ret) {
    //     new (&mResult) T(std::move(ret));
    //     return std::suspend_always();
    // }

    // 返回引用，这样外面就可以将result移动出去。（而不是拷贝？）
    T result() {
        if (mException) [[unlikely]] {
            std::rethrow_exception(mException);
        }
        return mResult.moveValue();
    }

    std::coroutine_handle<Promise> get_return_object() {
        return std::coroutine_handle<Promise>::from_promise(*this);
    }

    // 父调用者协程的句柄
    std::coroutine_handle<> mPrevious{};
    std::exception_ptr mException{};
    Uninitialized<T> mResult;
    // Promise() noexcept {}
    // Promise(Promise &&) = delete;
    // ~Promise() {}

    Promise &operator=(Promise &&) = delete;
};

template <>
struct Promise<void> {
    auto initial_suspend() {
        return std::suspend_always();
    }

    auto final_suspend() noexcept {
        return PreviousAwaiter(mPrevious);
    }

    void unhandled_exception() {
        debug(), "unhandled_exception";
        mException = std::current_exception();
    }

    void return_void() {}

    void result() {
        if (mException) [[unlikely]] {
            std::rethrow_exception(mException);
        }
    }

    // 返回当前promise对应的句柄。 就是说，从promise转化成对应的协程句柄，使用from_promise(*this)函数
    // 然后由于是协程句柄类型，所以前面是std::coroutine_handle<Promise>::
    std::coroutine_handle<Promise> get_return_object() {
        return std::coroutine_handle<Promise>::from_promise(*this);
    }

    // 父调用者协程的句柄
    std::coroutine_handle<> mPrevious = nullptr;

    // 返回值
    std::exception_ptr mException{};

    Promise() = default;
    Promise(Promise &&) = delete;
    ~Promise() = default;
};

template <class T>
struct Task {
    using promise_type = Promise<T>;

    Task(std::coroutine_handle<promise_type> coroutine)
        : mCoroutine(coroutine) {}

    // 为什么说根据“三无法则”就要写这一行？移动构造？
    Task(Task &&) = delete;

    ~Task() {
        mCoroutine.destroy();
    }

    struct Awaiter {
        bool await_ready() const noexcept {
            return false;
        }

        std::coroutine_handle<>
        await_suspend(std::coroutine_handle<> coroutine) const noexcept {
            // 和上面反过来，从协程句柄找到对应的promise，然后设置父协程句柄。
            mCoroutine.promise().mPrevious = coroutine;

            return mCoroutine;
        }

        // 返回协程co_return的返回值值。
        T await_resume() const noexcept {
            return mCoroutine.promise().result();
        }

        std::coroutine_handle<promise_type> mCoroutine;
    };

    auto operator co_await() const noexcept {
        return Awaiter(mCoroutine);
    }

    operator std::coroutine_handle<>() const noexcept {
        return mCoroutine;
    }

    std::coroutine_handle<promise_type> mCoroutine;
};

// 调度器
struct Loop {
    std::deque<std::coroutine_handle<>> mReadyQueue;

    struct TimerEntry {
        std::chrono::system_clock::time_point expireTime;
        std::coroutine_handle<> coroutine;

        // 重载<运算符，与大顶堆配合使用
        bool operator<(TimerEntry const &that) const noexcept {
            return expireTime > that.expireTime;
        }
    };

    // 大顶堆，top返回最大的值
    std::priority_queue<TimerEntry> mTimerHeap;

    void addTask(std::coroutine_handle<> t) {
        mReadyQueue.push_front(t);
    }

    void addTimer(std::chrono::system_clock::time_point expireTime,
                  std::coroutine_handle<> t) {
        mTimerHeap.push({expireTime, t});
    }

    void runAll() {
        while (!mTimerHeap.empty() || !mReadyQueue.empty()) {
            while (!mReadyQueue.empty()) {
                auto readyTask = mReadyQueue.front();
                debug(), "pop";
                mReadyQueue.pop_front();
                readyTask.resume();
            }
            if (!mTimerHeap.empty()) {
                auto nowTime = std::chrono::system_clock::now();
                auto timer = std::move(mTimerHeap.top());
                if (timer.expireTime < nowTime) {
                    mTimerHeap.pop();
                    // mReadyQueue.push_back(timer.coroutine);
                    // continue;
                    timer.coroutine.resume();
                } else {
                    std::this_thread::sleep_until(timer.expireTime);
                }
            }
        }
    }

    // 为了防止一不小心拷贝了。
    // 所以把移动赋值删了，这样其他的构造函数也都默认删了（但是保留默认构造）。
    Loop &operator=(Loop &&) = delete;
};

Loop &getLoop() {
    // loop作为全局变量，只会构造一次（单例模式）
    static Loop loop;
    return loop;
}

struct SleepAwaiter {
    bool await_ready() const {
        return std::chrono::system_clock::now() >= mExpireTime;
    }

    std::coroutine_handle<>
    await_suspend(std::coroutine_handle<> coroutine) const {
        getLoop().addTimer(mExpireTime, coroutine);
        return std::noop_coroutine();
    }

    void await_resume() const noexcept {}

    std::chrono::system_clock::time_point mExpireTime;
};

Task<void> sleep_until(std::chrono::system_clock::time_point expireTime) {
    co_await SleepAwaiter(expireTime);
    co_return;
}

Task<void> sleep_for(std::chrono::system_clock::duration duration) {
    co_await SleepAwaiter(std::chrono::system_clock::now() + duration);
    co_return;
}

struct ReturnPreviousPromise {
    auto initial_suspend() noexcept {
        return std::suspend_always();
    }

    auto final_suspend() noexcept {
        return PreviousAwaiter(mPrevious);
    }

    void unhandled_exception() {
        // throw;
        mException = std::current_exception();
    }

    void return_value(std::coroutine_handle<> previous) noexcept {
        // 协程结束时，保存前一个协程的句柄，用于协程间的控制流回溯
        mPrevious = previous;
    }

    auto get_return_object() {
        return std::coroutine_handle<ReturnPreviousPromise>::from_promise(
            *this);
    }

    void rethrow_if_any() {
        if (mException) [[unlikely]] {
            std::rethrow_exception(mException);
        }
    }

    std::coroutine_handle<> mPrevious{};
    std::exception_ptr mException{};

    ReturnPreviousPromise &operator=(ReturnPreviousPromise &&) = delete;
};

struct ReturnPreviousTask {
    using promise_type = ReturnPreviousPromise;

    ReturnPreviousTask(std::coroutine_handle<promise_type> coroutine) noexcept
        : mCoroutine(coroutine) {}

    ReturnPreviousTask(ReturnPreviousTask &&) = delete;

    ~ReturnPreviousTask() {
        mCoroutine.destroy();
    }

    std::coroutine_handle<promise_type> mCoroutine;
};

struct WhenAllCounterBlock {
    // mCount减为0的时候，唤醒
    std::size_t mCount;
    std::coroutine_handle<> mPrevious;
};

struct WhenAllAwaiter {
    bool await_ready() const noexcept {
        return false;
    }

    std::coroutine_handle<>
    await_suspend(std::coroutine_handle<> coroutine) const {
        counter.mPrevious = coroutine;
        getLoop().addTask(t2.mCoroutine);
        return t1.mCoroutine;
    }

    void await_resume() const noexcept {
        t1.mCoroutine.promise().rethrow_if_any();
        t2.mCoroutine.promise().rethrow_if_any();
    }

    WhenAllCounterBlock &counter;
    ReturnPreviousTask const &t1;
    ReturnPreviousTask const &t2;
};

// struct CounterBlock {
//     // mCount减为0的时候，唤醒
//     std::size_t mCount;
//     std::coroutine_handle<> mPrevious;
// }

template <class T>
ReturnPreviousTask whenAllHelper(Task<T> const &t, WhenAllCounterBlock &counter,
                                 Uninitialized<T> &result) {
    result.putValue(co_await t);
    counter.mCount--;
    std::coroutine_handle<> previous = nullptr;
    if (counter.mCount == 0) {
        previous = counter.mPrevious;
    }
    co_return previous;
}

template <class T1, class T2>
Task<std::tuple<T1, T2>> when_all(Task<T1> const &t1, Task<T2> const &t2) {
    WhenAllCounterBlock counter;
    std::tuple<Uninitialized<T1>, Uninitialized<T2>> result;
    counter.mCount = 2; // 初始化为任务的数量
    co_await WhenAllAwaiter(counter,
                            whenAllHelper(t1, counter, std::get<0>(result)),
                            whenAllHelper(t2, counter, std::get<1>(result)));
    co_return std::tuple<T1, T2>(std::get<0>(result).moveValue(),
                                 std::get<1>(result).moveValue());
}

Task<int> hello1() {
    debug(), "hello1 begin to sleep 1s";
    co_await sleep_for(1s);
    debug(), "hello1 had sleep for 1s done";
    co_return 1;
}

Task<int> hello2() {
    debug(), "hello2 begin to sleep 2s";
    co_await sleep_for(2s);
    debug(), "hello2 had sleep 2s done";
    co_return 2;
}

Task<int> hello() {
    debug(), "hello开始等1和2";
    auto [r1, r2] = co_await when_all(hello1(), hello2());
    debug(), "1 和2都睡醒了";
    co_return r1 + r2;
}

int main() {
    auto t = hello();
    getLoop().addTask(t);
    getLoop().runAll();
    debug(), "主函数中得到hello结果：", t.mCoroutine.promise().result();
    return 0;
}
